/**
 * 实现文件读写、信息处理和表格代码转换
 * 创建者：Carburn Ashroom
 * 2024.6.19
 */

#include "code.h"

namespace Code {

    QString Table::text() const
    {
        QString text;
        QTextStream t_str {&text};
        t_str << pre_text << "start\n";
        for (const auto& c : const_classes())
            t_str << c.text();
        t_str << "end\n" << end_text;
        return text;
    }

    void Table::read(const QString& table)
    {
        if (table.indexOf("\nstart\n") == -1)
            throw No_start_error{};
        else if (table.indexOf("\nend\n") == -1)
            throw No_end_error{};
        QString rt {table};
        QTextStream f_str {&rt};
        pre_text.clear();
        for (QString line{f_str.readLine()}; line!="start"; line=f_str.readLine())
            pre_text += line+'\n';
        QList<Chess::Class> bkp {std::move(avail_classes())};
        avail_classes() = QList<Chess::Class>{};
        try {
            for (QString line{f_str.readLine()}; line!="end"; line=f_str.readLine()) {
                if (line.isEmpty() or line.left(2)=="//")
                    continue;
                append(Chess::Message{std::move(line)});
            }
        }
        catch (const Chess::Format_error& err) {
            avail_classes() = std::move(bkp);
            throw;
        }
        end_text = f_str.readAll();
    }

    void Table::write() const
    {
        QFile save {file};
        save.open(QIODevice::WriteOnly);
        QTextStream s_str {&save};
        s_str << text();
    }

    Base::Base_table Table::select(const Selector& selector) const
    {
        Base::Base_table result {pre_code_file,end_code_file};
        for (const auto& c : const_classes())
            result.append_class(c.get_type(), c.select(selector));
        return result;
    }

    void Pieces::add_piece(QChar piece)
    {
        auto& pieces = avail_pieces();
        if (is_clear()) {
            pieces.clear();
            set_chess(piece, 1);
            return;
        }
        int max_count {};
        for (auto& p : chess_max)
            if (p.first.contains(piece)) {
                max_count = p.second;
                break;
            }
        for (auto& p : pieces)
            if (p.first == piece) {
                if (p.second == max_count)
                    throw Full_error{};
                ++p.second;
                return;
            }
        pieces.emplaceBack(piece, 1);
    }

    void Pieces::clear()
    {
        avail_pieces().clear();
        set_chess(chess_king[red], 1);
    }

    void Pieces::del_piece(QChar piece)
    {
        if (chess_king.contains(piece))
            throw Del_king_error{};
        auto& pieces = avail_pieces();
        for (auto i=pieces.begin(); i!=pieces.end(); ++i)
            if (i->first == piece) {
                pieces.erase(i);
                break;
            }
        if (pieces.isEmpty())
            clear();
    }

}
